/*
 * Copyright 2007-2009 Thomas Krause (thomas@berlin-reloaded.de)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gidoo.cms.editor.history;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionIterator;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
import org.gidoo.cms.login.GidooCMSSession;
import org.gidoo.cms.editor.EditorPage;
import org.gidoo.cms.jcr.EditDataManager;
import org.gidoo.cms.publisher.PublisherPage;
import org.gidoo.wickettools.MessageBox;
import org.gidoo.wickettools.XHTMLDiff;

/**
 *
 * @author <a href="mailto:thomas@berlin-reloaded.de">Thomas Krause</a>
 */
public class HistoryPanel extends Panel
{
  
  private EditorPage parentPage;
  private String pagePath;
  
  private ListView<String> lsvRevisions;
  private List<String> history;
  
  public HistoryPanel(String id, final Node page, EditorPage parent)
  {
    super(id);
    try
    {
      if(page == null)
      {
        this.pagePath = null;
      }
      else
      {  
        this.pagePath = page.getPath().substring(1);
      }
      this.parentPage = parent;

      Form formMain = new Form("formMain");

      history = new ArrayList<String>();
      if(page != null)
      {
        VersionIterator it = page.getVersionHistory().getAllVersions();
        while(it.hasNext())
        {
          Version v = it.nextVersion();
          Node revisonAsNode = v.getNode("jcr:frozenNode");
          // only add non-empty nodes
          if(revisonAsNode.hasProperty("cms:title") && revisonAsNode.hasProperty("cms:xml"))
          {
            history.add(v.getName());
          }
        }
      }

      Label lblNoOldRevisions = new Label("lblNoOldRevisions",
        new ResourceModel("nooldrevisions"));
      lblNoOldRevisions.setVisible(history.isEmpty());
      formMain.add(lblNoOldRevisions);

      lsvRevisions = new ListView<String>("lsvRevisions", history)
      {

        @Override
        protected void populateItem(ListItem<String> item)
        {
          try
          {
            final String revName = item.getModelObject();
            final String prevName = item.getIndex() > 0 ? history.get(item.getIndex() - 1) : null;
            Version rev = getVersionFromName(revName);

            Link lnkDiffPrev = new Link("lnkDiffPrev")
            {

              @Override
              public void onClick()
              {
                try
                {
                  Version rev = getVersionFromName(revName);
                  Version prev = getVersionFromName(prevName);
                  diffToPrevious(rev.getNode("jcr:frozenNode"), prev.getNode("jcr:frozenNode"));
                }
                catch(RepositoryException ex)
                {
                  Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
                  error(getString("jcrerror"));
                }
              }
            };
            lnkDiffPrev.setVisible(item.getIndex() > 0);
            item.add(lnkDiffPrev);

            item.add(new Link("lnkDiffCur")
            {

              @Override
              public void onClick()
              {
                try
                {
                  Version rev = getVersionFromName(revName);
                  diffToCurrent(rev.getNode("jcr:frozenNode"));
                }
                catch(RepositoryException ex)
                {
                  Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
                  error(getString("jcrerror"));
                }
              }
            });
            DateFormat d = DateFormat.getDateTimeInstance();
            String ds = getString("unknown");

            if(rev.getCreated() != null)
            {
              Date date = new Date(rev.getCreated().getTimeInMillis());
              ds = d.format(date);
            }
            item.add(new Label("lblDate", new Model(ds)));

            String author = getString("unknown");
            Node revNode = rev.getNode("jcr:frozenNode");
            if(revNode.hasProperty("cms:editor"))
            {
              author = revNode.getProperty("cms:editor").getString();
            }
            item.add(new Label("lblAuthor", new Model(author)));

            item.add(new AjaxLink("lnkRestore")
            {

              @Override
              public void onClick(AjaxRequestTarget target)
              {
                try
                {
                  Version rev = getVersionFromName(revName);
                  restore(rev);
                  info(getString("waitingforpublisher"));
                }
                catch(RepositoryException ex)
                {
                  Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
                  error(getString("jcrerror"));
                }
                
                target.addComponent(parentPage.getFeedbackPanel());
              }
            });
          }
          catch(RepositoryException ex)
          {
            Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
            error(getString("jcrerror"));
          }
        }
      };
      formMain.add(lsvRevisions);

      add(formMain);
      if(page == null)
      {
        formMain.setVisible(false);
      }
    }
    catch(RepositoryException ex)
    {
      Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("jcrerror"));
    }
  }
  
  
  private void restore(Version oldRev) throws RepositoryException
  {
    Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
    Node currentPage = rootNode.getNode(pagePath);
    Node oldRevAsNode = oldRev.getNode("jcr:frozenNode");
    
    EditDataManager.createDraft(currentPage, false,
      oldRevAsNode.getProperty("cms:title").getString(), 
      oldRevAsNode.getProperty("cms:xml").getString(),
      (GidooCMSSession) getSession());
  }
  
  private void diffToCurrent(Node old) throws RepositoryException
  {

    Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();

    if(pagePath == null || !rootNode.hasNode(pagePath))
    {
      error(getString("error"));
      return;
    }

    Node page = rootNode.getNode(pagePath);

    if(!old.hasProperty("cms:xml") || !old.hasProperty("cms:title"))
    {
      warn(getString("emptyxml"));
      return;
    }
    
    String diff = XHTMLDiff.doDiff(old.getProperty("cms:xml").getString(), 
      page.getProperty("cms:xml").getString(),
      getString("old"), getString("current"));

    String msg = PublisherPage.wrapDiff(getString("oldtitle"),
      old.getProperty("cms:title").getString(),
      getString("newtitle"), page.getProperty("cms:title").getString(), diff);

    MessageBox msgBox = new MessageBox(getString("diffoldcurrent"), msg, true, MessageBox.MessageBoxButtons.OK, parentPage, null);

    setResponsePage(msgBox);
  }
 
  private void diffToPrevious(Node revNewer, Node revOlder) throws RepositoryException
  {
    Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();

    if(pagePath == null || !rootNode.hasNode(pagePath) || revNewer == null || revOlder == null)
    {
      error(getString("error"));
      return;
    }
    
    if(!revNewer.hasProperty("cms:xml") || !revNewer.hasProperty("cms:title")
      || !revOlder.hasProperty("cms:xml") || !revOlder.hasProperty("cms:title"))
    {
      warn(getString("emptyxml"));
      return;
    }
    
    String diff = XHTMLDiff.doDiff(revOlder.getProperty("cms:xml").getString(), 
      revNewer.getProperty("cms:xml").getString(),
      getString("old"), getString("newer"));

    String msg = PublisherPage.wrapDiff(getString("oldtitle"),
      revOlder.getProperty("cms:title").getString(),
      getString("newtitle"), revNewer.getProperty("cms:title").getString(), diff);

    MessageBox msgBox = new MessageBox(getString("diffoldcurrent"), msg, true, MessageBox.MessageBoxButtons.OK, parentPage, null);

    setResponsePage(msgBox);
  }

  private Version getVersionFromName(String name) throws RepositoryException
  {
    Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
    Node currentPage = rootNode.getNode(pagePath);

    Version result = currentPage.getVersionHistory().getVersion(name);
    return result;

  }
  
  public void updateDataAndView(Node page, EditorPage parent)
  {
    try
    {
      if(parent == null)
      {
        throw new NullPointerException();
      }
      this.pagePath = page == null ? null : page.getPath().substring(1);
      this.parentPage = parent;

      this.history = new ArrayList<String>();
      if(page != null)
      {
        VersionIterator it = page.getVersionHistory().getAllVersions();
        while(it.hasNext())
        {
          Version v = it.nextVersion();
          history.add(v.getName());
        }
      }
      
      lsvRevisions.setList(history);
    }
    catch(RepositoryException ex)
    {
      Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("jcrerror"));
    }
  }

}
